package com.ruoyi.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.utils.uuid.Seq;
import com.ruoyi.system.domain.MiniStock;
import com.ruoyi.system.domain.MiniStockSubject;
import com.ruoyi.system.domain.MiniSubject;
import com.ruoyi.system.domain.MiniSubjectHistory;
import com.ruoyi.system.domain.dto.SubjectImportDTO;
import com.ruoyi.system.domain.vo.h5.MainSubjectVO;
import com.ruoyi.system.mapper.MiniSubjectMapper;
import com.ruoyi.system.service.IMiniStockService;
import com.ruoyi.system.service.IMiniSubjectService;
import com.ruoyi.system.service.MiniStockSubjectService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 题材Service业务层处理
 * 
 * @author ruoyi
 * @date 2023-11-01
 */
@Service
@Slf4j
public class MiniSubjectServiceImpl extends ServiceImpl<MiniSubjectMapper, MiniSubject> implements IMiniSubjectService
{
    @Autowired
    private IMiniStockService miniStockService;
    @Autowired
    private MiniStockSubjectService miniStockSubjectService;
    /**
     * 查询题材
     * 
     * @param subjectId 题材主键
     * @return 题材
     */
    @Override
    public MiniSubject selectMiniSubjectBySubjectId(Long subjectId)
    {
        return this.getBaseMapper().selectMiniSubjectBySubjectId(subjectId);
    }

    /**
     * 查询题材列表
     * 
     * @param miniSubject 题材
     * @return 题材
     */
    @Override
    public List<MiniSubject> selectMiniSubjectList(MiniSubject miniSubject)
    {
        return this.getBaseMapper().selectMiniSubjectList(miniSubject);
    }

    /**
     * 新增题材
     * 
     * @param miniSubject 题材
     * @return 结果
     */
    @Override
    public int insertMiniSubject(MiniSubject miniSubject)
    {
        MiniSubject info = this.getBaseMapper().selectMiniSubjectBySubjectId(miniSubject.getParentId());
        // 如果父节点不为正常状态,则不允许新增子节点
        if (!UserConstants.DEPT_NORMAL.equals(info.getStatus()))
        {
            throw new ServiceException("父题材停用，不允许新增");
        }
        miniSubject.setAncestors(info.getAncestors() + "," + miniSubject.getParentId());
        miniSubject.setLevel(info.getLevel()+1);
        if (miniSubject.getLevel() != 1 && miniSubject.getMainSort()>0){
            throw new ServiceException("题材父级为“全部题材”时才能设置主线排序！");
        }
        return this.getBaseMapper().insertMiniSubject(miniSubject);
    }

    /**
     * 修改题材
     * 
     * @param miniSubject 题材
     * @return 结果
     */
    @Override
    public int updateMiniSubject(MiniSubject miniSubject)
    {
        miniSubject.setUpdateTime(DateUtils.getNowDate());
        return this.getBaseMapper().updateMiniSubject(miniSubject);
    }

    /**
     * 批量删除题材
     * 
     * @param subjectIds 需要删除的题材主键
     * @return 结果
     */
    @Override
    public int deleteMiniSubjectBySubjectIds(Long[] subjectIds)
    {
        return this.getBaseMapper().deleteMiniSubjectBySubjectIds(subjectIds);
    }

    /**
     * 删除题材信息
     * 
     * @param subjectId 题材主键
     * @return 结果
     */
    @Override
    public int deleteMiniSubjectBySubjectId(Long subjectId)
    {
        return this.getBaseMapper().deleteMiniSubjectBySubjectId(subjectId);
    }

    /**
     * 校验题材名称是否唯一
     *
     * @param miniSubject 题材信息
     * @return 结果
     */
    @Override
    public boolean checkSubjectNameUnique(MiniSubject miniSubject) {
        Long miniSubjectId = StringUtils.isNull(miniSubject.getSubjectId()) ? -1L : miniSubject.getSubjectId();
        MiniSubject info = this.getBaseMapper().checkSubjectNameUnique(miniSubject.getName(), miniSubject.getParentId());
        if (StringUtils.isNotNull(info) && info.getSubjectId().longValue() != miniSubjectId.longValue())
        {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 根据ID查询所有子部门（正常状态）
     *
     * @param subjectId 部门ID
     * @return 子部门数
     */
    @Override
    public int selectNormalChildrenSubjectById(Long subjectId) {
        return this.getBaseMapper().selectNormalChildrenSubjectById(subjectId);
    }

    /**
     * 是否存在题材子节点
     *
     * @param subjectId 题材ID
     * @return 结果
     */
    @Override
    public boolean hasChildBySubjectId(Long subjectId) {
        int result = this.getBaseMapper().hasChildBySubjectId(subjectId);
        return result > 0;
    }

    /**
     * 通过id列表查询题材
     *
     * @param subjectIds
     * @param level
     * @return
     */
    @Override
    public List<MiniSubject> selectMiniSubjectBySubjectIdList(List<Long> subjectIds, int level) {
        return this.getBaseMapper().selectMiniSubjectBySubjectIdList(subjectIds, level);
    }

    /**
     * 批量更新涨幅
     *
     * @param updateSubjectList
     */
    @Override
    public void batchUpdateRate(List<MiniSubject> updateSubjectList) {
        this.getBaseMapper().batchUpdateRate(updateSubjectList);
    }

    /**
     * 把题材所有的涨幅度都更新为0
     */
    @Override
    public void updateAllRateZero() {
        this.getBaseMapper().updateAllRateZero();
    }

    /**
     * 获取上一层的涨幅度
     *
     * @param maxLevel
     * @return
     */
    @Override
    public List<MiniSubject> getParentRate(int maxLevel) {
        return this.getBaseMapper().getParentRate(maxLevel);
    }

    /**
     * 查热点题材
     *
     * @return
     */
    @Override
    public List<MiniSubject> selectHotData() {
        return this.list(Wrappers.<MiniSubject>lambdaQuery().gt(MiniSubject::getImportance,0)
                .eq(MiniSubject::getDelFlag,0)
                .eq(MiniSubject::getStatus,0)
                .eq(MiniSubject::getLevel,1)
                .orderByAsc(MiniSubject::getImportance));
    }

    /**
     * 把今天数据查出来
     *
     * @return
     */
    @Override
    public List<MiniSubjectHistory> selectSubjectHistory() {
        return this.getBaseMapper().selectSubjectHistory();
    }

    /**
     * 查父题材有没有股票
     *
     * @param subjectId
     * @return
     */
    @Override
    public boolean checkSubjectHaveStock(Long subjectId) {
        List<MiniStock> list = miniStockService.getMiniStockListBySubjectIds(Collections.singletonList(subjectId));
        return !list.isEmpty();
    }

    @Override
    public List<MiniSubject> selectHot2Data() {
        return this.list(Wrappers.<MiniSubject>lambdaQuery().gt(MiniSubject::getRate,0)
                .eq(MiniSubject::getDelFlag,0)
                .eq(MiniSubject::getStatus,0)
                .eq(MiniSubject::getLevel,1)
                .eq(MiniSubject::getImportance,0)
                .orderByDesc(MiniSubject::getRate));
    }

    @Override
    public int updateSubjectStock(MiniStockSubject stockSubject) {
        Long subjectId = stockSubject.getSubjectId();
        miniStockSubjectService.remove(Wrappers.<MiniStockSubject>lambdaQuery().eq(MiniStockSubject::getSubjectId,subjectId));
        if (CollUtil.isNotEmpty(stockSubject.getSelectedStockIds())){
            List<MiniStock> stocks = miniStockService.listByIds(stockSubject.getSelectedStockIds());
            List<MiniStockSubject> insertList = new ArrayList<>();
            for (MiniStock stock : stocks) {
                insertList.add(new MiniStockSubject(stock.getId(), stock.getStockNo(), stock.getName(),subjectId));
            }
            miniStockSubjectService.saveBatch(insertList);
        }
        return 1;
    }

    @Override
    public List<MiniSubjectHistory> getParentRateMoneyInflow(int level) {
        return this.getBaseMapper().getParentRateMoneyInflow(level);
    }

    @Override
    public AjaxResult importData(MultipartFile file, boolean updateSupport, String username, Date nowDate) throws Exception {
        ExcelUtil<SubjectImportDTO> util = new ExcelUtil<>(SubjectImportDTO.class);
        LinkedHashMap<String, List<SubjectImportDTO>> sheetMap = util.importExcelAllSheet(file.getInputStream());
        String errorMsg = dealSheetMap(username, nowDate, sheetMap);
        if (StringUtils.isNotBlank(errorMsg)){
            return AjaxResult.error(errorMsg);
        }
        return AjaxResult.success("导入成功");
    }

    @Override
    public List<MainSubjectVO> mainSubject() {
        return this.getBaseMapper().mainSubject();
    }

    @Override
    public List<MiniSubject> selectSubjectOneAndFour(List<SubjectImportDTO> allRows) {
        return this.getBaseMapper().selectSubjectOneAndFour(allRows);
    }

    public String dealSheetMap(String username, Date nowDate, LinkedHashMap<String, List<SubjectImportDTO>> sheetMap) {
        Set<String> allSubjectNameList = new HashSet<>();
        Set<String> allStockNoList = new HashSet<>();
        List<SubjectImportDTO> allRows = new ArrayList<>();
        sheetMap.forEach((k, v) -> {
            SubjectImportDTO lastRow = new SubjectImportDTO();
            allRows.addAll(v);
            for (int i = 0; i < v.size(); i++) {
                SubjectImportDTO dto = v.get(i);
                if (i>0){
                    if (StringUtils.isBlank(dto.getSubjectNameOne())){
                        dto.setSubjectNameOne(lastRow.getSubjectNameOne());
                    }
                    if (StringUtils.isBlank(dto.getSubjectNameTwo())){
                        dto.setSubjectNameTwo(lastRow.getSubjectNameTwo());
                    }
                    if (StringUtils.isBlank(dto.getSubjectNameThree())){
                        dto.setSubjectNameThree(lastRow.getSubjectNameThree());
                    }
                    if (StringUtils.isBlank(dto.getSubjectNameFour())){
                        dto.setSubjectNameFour(lastRow.getSubjectNameFour());
                    }
                }
                BeanUtil.copyProperties(dto,lastRow);
                allSubjectNameList.add(dto.getSubjectNameOne());
                allSubjectNameList.add(dto.getSubjectNameTwo());
                allSubjectNameList.add(dto.getSubjectNameThree());
                allSubjectNameList.add(dto.getSubjectNameFour());
                allStockNoList.add(dto.getStockNo());
            }
        });
        Map<String, MiniSubject> existSubjectMap = this.list(Wrappers.<MiniSubject>lambdaQuery().in(MiniSubject::getName, new ArrayList<>(allSubjectNameList)).eq(MiniSubject::getDelFlag,0))
                .stream().collect(Collectors.toMap(it->it.getName()+"_"+it.getLevel(), Function.identity(), (v1, v2) -> v1));
        //只取name,level值
        Map<String, MiniSubject> existSubjectFourMap = this.selectSubjectOneAndFour(allRows)
                .stream().collect(Collectors.toMap(it->it.getName()+"_"+it.getLevel(), Function.identity(), (v1, v2) -> v1));
        final List<MiniStock> existStockList = miniStockService.list(Wrappers.<MiniStock>lambdaQuery().in(MiniStock::getStockNo, new ArrayList<>(allStockNoList)).eq(MiniStock::getDeleted, 0));
        Map<String, MiniStock> existStocktMap = existStockList.stream().collect(Collectors.toMap(MiniStock::getStockNo, Function.identity(), (v1, v2) -> v1));
        final Map<String, MiniStockSubject> existStockSubjectMap = miniStockSubjectService.list(Wrappers.<MiniStockSubject>lambdaQuery().in(MiniStockSubject::getStockNo, allStockNoList))
                .stream().collect(Collectors.toMap(it -> it.getStockNo() + "_" + it.getSubjectId(), Function.identity(), (v1, v2) -> v1));
        // Map<String, MiniSubject> existSubjectMap = new HashMap<>();
        // Map<String, MiniStock> existStocktMap = new HashMap<>();
        StringBuilder errorMsg = new StringBuilder();

        List<MiniSubject> subjectAddList = new ArrayList<>();
        List<MiniStock> stockAddList = new ArrayList<>();
        List<MiniStock> stockUpdateList = new ArrayList<>();
        List<MiniStockSubject> stockSubjectAddList = new ArrayList<>();
        for (Map.Entry<String, List<SubjectImportDTO>> entry : sheetMap.entrySet()) {
            String k = entry.getKey();
            List<SubjectImportDTO> v = entry.getValue();
            int sheetSize = v.size();
            log.info("sheetName:{}处理开始，总行数:{}",k, sheetSize);
            for (int i = 0; i < sheetSize; i++) {
                MiniSubject parentSubject = new MiniSubject();
                StringBuilder rowMsg = new StringBuilder().append(k).append("页的第").append(i + 1).append("行：");
                SubjectImportDTO row = v.get(i);
                rowCheck(i, row, errorMsg, rowMsg);
                String stockNo = row.getStockNo();
                nameToSubject(i,row.getSubjectNameOne(),1,subjectAddList,parentSubject,existSubjectMap,username,nowDate);
                nameToSubject(i,row.getSubjectNameTwo(),2,subjectAddList,parentSubject, existSubjectMap, username, nowDate);
                nameToSubject(i,row.getSubjectNameThree(),3,subjectAddList,parentSubject, existSubjectMap, username, nowDate);
                nameToSubject(i,row.getSubjectNameFour()+"_"+row.getSubjectNameOne(),4,subjectAddList,parentSubject, existSubjectFourMap, username, nowDate);

                toStock(i,row,existStocktMap,parentSubject,stockAddList,stockSubjectAddList,username,nowDate,stockUpdateList,existStockSubjectMap);
            }
        }
        log.info("导入的题材添加列表:{}",JSON.toJSONString(subjectAddList));
        log.info("导入的股票添加列表:{}",JSON.toJSONString(stockAddList));
        log.info("导入的股票题材关系添加列表:{}",JSON.toJSONString(stockSubjectAddList));
        log.info("更新股票列表:{}",JSON.toJSONString(stockUpdateList));
        String errorMsgString = errorMsg.toString();
        if (StringUtils.isBlank(errorMsgString)){
            this.saveBatch(subjectAddList);
            miniStockService.saveBatch(stockAddList);
            miniStockSubjectService.saveBatch(stockSubjectAddList);
            miniStockService.updateBatchById(stockUpdateList);
            return null;
        }
        return errorMsgString;
    }

    private static void toStock(int i, SubjectImportDTO row, Map<String, MiniStock> existStocktMap, MiniSubject parentSubject, List<MiniStock> stockAddList, List<MiniStockSubject> stockSubjectAddList, String username, Date nowDate, List<MiniStock> stockUpdateList, Map<String, MiniStockSubject> existStockSubjectMap) {
        String stockNo = row.getStockNo();
        if (existStocktMap.containsKey(stockNo)){
            MiniStock stock = existStocktMap.get(stockNo);
            if (!existStockSubjectMap.containsKey(stockNo + "_" + parentSubject.getSubjectId())){
                stockSubjectAddList.add(new MiniStockSubject(stock.getId(), stockNo, row.getStockName(), parentSubject.getSubjectId()));
            }
            stockUpdateList.add(new MiniStock(stock.getId(),i,row.getDescription(),username));
            return;
        }
        Long id = Long.valueOf(Seq.getId());
        stockSubjectAddList.add(new MiniStockSubject(id, stockNo, row.getStockName(), parentSubject.getSubjectId()));
        stockAddList.add(new MiniStock(id, stockNo, row.getStockName(), i, row.getDescription(), username, nowDate));
    }

    private static void nameToSubject(int i, String name, int level, List<MiniSubject> addList, MiniSubject parentSubject, Map<String, MiniSubject> existSubjectMap, String username, Date nowDate) {
        int paramLevel = level;
        if (StringUtils.isBlank(name)){
            return;
        }
         level = level == 1 ?level:parentSubject.getLevel()+1;
        MiniSubject existSubject = existSubjectMap.get(name + "_" + level);
        if (existSubject ==null){
            MiniSubject addEntity;
            if (paramLevel==4){
                addEntity = buildAddEntity(username, nowDate, name.split("_")[0] , level ==1 ? 1L:parentSubject.getSubjectId(), level, level ==1 ? "0,1":parentSubject.getAncestors(), i);
            }else{
                addEntity = buildAddEntity(username, nowDate, name, level ==1 ? 1L:parentSubject.getSubjectId(), level, level ==1 ? "0,1":parentSubject.getAncestors(), i);
            }
            addList.add(addEntity);
            BeanUtil.copyProperties(addEntity,parentSubject);
            existSubjectMap.put(name + "_" + level,addEntity);
        }else{
            BeanUtil.copyProperties(existSubject,parentSubject);
        }
    }

    public static MiniSubject buildAddEntity(String username, Date nowDate, String name, Long parentId, Integer currentLevel, String ancestors, int i) {
        Long id = Long.valueOf(Seq.getId());
        return new MiniSubject(id,parentId, currentLevel ==1 ?ancestors:ancestors+","+parentId,name,i,currentLevel,username,nowDate);
    }

    public static void rowCheck(int i, SubjectImportDTO row, StringBuilder errorMsg, StringBuilder rowMsg) {
        String stockNo = row.getStockNo();
        if (i == 0) {
            if (StringUtils.isBlank(row.getSubjectNameOne())){
                errorMsg.append(rowMsg).append("概念名称不能为空;");
            }
            if (StringUtils.isBlank(row.getSubjectNameTwo())&&StringUtils.isNotBlank(row.getSubjectNameThree())){
                errorMsg.append(rowMsg).append("概念细分二级为空的时候概念细分三级不能填写;");
            }
            if (StringUtils.isBlank(row.getSubjectNameFour())){
                errorMsg.append(rowMsg).append("相关业务没有填写;");
            }
        }
        if (StringUtils.isBlank(stockNo)){
            errorMsg.append(rowMsg).append("股票代码没有填写;");
        }
        if (stockNo.length()!=6||!stockNo.matches("\\d+")){
            errorMsg.append(rowMsg).append("股票代码为6位数字;");
        }
    }


    public static void main(String[] args) throws Exception {
        InputStream is = Files.newInputStream(new File("D:\\learn\\概念细分_test).xlsx").toPath());
        ExcelUtil<SubjectImportDTO> util = new ExcelUtil<>(SubjectImportDTO.class);
        LinkedHashMap<String, List<SubjectImportDTO>> sheetMap = util.importExcelAllSheet(is);
        // dealSheetMap("1",DateUtils.getNowDate(),sheetMap);
    }
}
